package particlesystem.core {
	import particlesystem.effects.IEffect;
	import particlesystem.graphics.BitmapAnimation;

	import flash.display.BitmapData;

	/**
	 * @author robertthurston
	 */
	public class ParticleEffect {

		private var particleSettings : ParticleSettings;
		private var particleDataArray : Array;
		private var totalParticles : uint;
		private var canvas : ParticleCanvas;
		private var effects : Array;
		private var alphaBitmapDataArray : Array;
		private var killRequested : Boolean;

		public function ParticleEffect(particleSettings : ParticleSettings, canvas : ParticleCanvas) {
			this.canvas = canvas;
			this.particleSettings = particleSettings;
			
			particleDataArray = new Array();
			effects = new Array();
			
			createAlphasThisNeedsMovingAsTempLocation();
		}

		private function createAlphasThisNeedsMovingAsTempLocation() : void {
			alphaBitmapDataArray = new Array();
			
			var colours : Array = [0x11FFFFFF, 0x22FFFFFF, 
									0x33FFFFFF, 0x55FFFFFF,
									0x66FFFFFF, 0x88FFFFFF,
									0x99FFFFFF, 0xBBFFFFFF,
									0xDDFFFFFF,	0xEEFFFFFF];
				
			for(var i : int = 0;i < colours.length;i++) {
				var bitmapData : BitmapData = new BitmapData(25, 25, true, colours[i]);
				alphaBitmapDataArray.push(bitmapData);
			}
		}

		public function addParticles(quantity : int) : void {
			for(var i : int = 0;i < quantity;i++) {
				var particleData : ParticleData = new ParticleData(alphaBitmapDataArray);
				
				applyParticleSettings(particleData);
				
				particleDataArray.push(particleData);
			}
			
			totalParticles = particleDataArray.length;
		}

		public function removeParticles() : void {
			totalParticles = 0;
			particleDataArray = new Array();
		}

		public function addEffect(effect : IEffect) : void {
			effects.push(effect);
		}

		private function applyParticleSettings(particleData : ParticleData) : void {
			particleData.x = particleSettings.startX;
			particleData.y = particleSettings.startY;
			particleData.reSpawn = particleSettings.reSpawn;
			particleData.startDelay = particleSettings.startDelay;
			particleData.bitmapAnimation = new BitmapAnimation(particleSettings.getRandomBitmapAnimationParticle(), true);
			
			for(var i : int = 0;i < effects.length;i++) {
				IEffect(effects[i]).reset(particleData);				
			}
		}

		public function update() : void {
			var needsCompacting : Boolean;
			
			canvas.lock();
			
			for (var i : int = 0;i < totalParticles;i++) {
				var particleData : ParticleData = particleDataArray[i];				
				
				if(particleData.startDelay > 0) {
					particleData.startDelay--;
				} else if(particleData.life > 1) {
					updateEffects(particleData);
					canvas.copyPixels(particleData.nextFrame, particleData.x, particleData.y, particleData.alphaBitmapData);
				}else if(particleData.reSpawn) {
					applyParticleSettings(particleData);
				} else {
					needsCompacting = true;
					particleDataArray[i] = null;
				}
			}
			
			canvas.unlock();
			
			if(needsCompacting) {
				compactArray(particleDataArray);
			}
			
			// NEED TO MOVE THIS AS NOT RIGHT!
			// MAYBE MOVE CREATION TO EMITTER
			if(killRequested) {
				kill();
				killRequested = false;
			}
		}

		public function killUnstartedParticles() : void {
			killRequested = true;
		}

		public function kill() : void {
			for (var i : int = 0;i < totalParticles;i++) {
				var particleData : ParticleData = particleDataArray[i];				
				
				if(particleData.startDelay > 0) {
					particleData.startDelay = 0;
					particleData.life = 0;
				}
				
				particleData.reSpawn = false;
			}
		}

		private function updateEffects(particleData : ParticleData) : void {
			for(var i : int = 0;i < effects.length;i++) {
				IEffect(effects[i]).update(particleData);				
			}
		}

		private function compactArray(array : Array) : void {
			for(var i : int = totalParticles - 1;i >= 0;i--) {
				if(array[i] == null) {
					array.splice(i, 1);
				}
			}
			
			totalParticles = array.length;
		}

		public function removeEffects() : void {
			effects = [];
		}
	}
}
